/*
 * Gedigarr - Falling block game.
 * Copyright (C) 2010  BoredCorp
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
package gedigarr.grid;

import gedigarr.game.GameConstants;
import gedigarr.game.GameScore;
import gedigarr.objects.CharacterCell;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import putil.Putil;

/**
 *
 * @author JC
 */
public class ScoreInputGrid extends TextGrid {

  public static final int STATE_INACTIVE = 0;
  public static final int STATE_ENTRY = 1;
  public static final int STATE_CONFIRMED = 2;
  private static final int STRING_LENGTH = 5;
  private static final int ALPHA_X = 0;
  private static final int ALPHA_Y = 14;
  private static final int ALPHA_WIDTH = GameConstants.GRID_WIDTH;
  private static final int ALPHA_HEIGHT = 4;
  private static final Color COLOUR_ACTIVE = Color.RED;
  private static final Color COLOUR_INACTIVE = Color.BLACK;
  private static final Color COLOUR_COMPLETE = Color.GREEN;
  public static final int MOVE_RIGHT = 1 << 0;
  public static final int MOVE_LEFT = 1 << 1;
  public static final int MOVE_UP = 1 << 2;
  public static final int MOVE_DOWN = 1 << 3;
  private char[] specialChars = new char[] {'←', '»'};
  private int moveFlags = 0;
  private int state = STATE_INACTIVE;
  private final GameScore gameScore;
  private long newScore = 0L;
  private char[] string = new char[STRING_LENGTH];
  private final Rectangle selectGrid = new Rectangle( ALPHA_X, ALPHA_Y, ALPHA_WIDTH, ALPHA_HEIGHT );
  private final Point selected = new Point();
  private final Point end = new Point( ALPHA_WIDTH - 1, ALPHA_HEIGHT - 1 );
  private int stringPos = 0;
  private int scoreBoard = -1;
  private boolean complete = false;

  public ScoreInputGrid( GameScore gameScore ) {
    this.gameScore = gameScore;
    grid = new CharacterCell[GameConstants.GRID_HEIGHT][GameConstants.GRID_WIDTH];
    for ( int y = 0; y < GameConstants.GRID_HEIGHT; y++ ) {
      for ( int x = 0; x < GameConstants.GRID_WIDTH; x++ ) {
        grid[y][x] = new CharacterCell( true, true, Color.BLACK, "images/trans.png" );
      }
    }
    writeKeyboard();
    reset();

  }

  private void reset() {
    newScore = 0L;
    complete = false;
    setCursor( 0, 0 );
    clearString();
    drawText();
  }

  private void clearString() {
    for ( int i = 0; i < STRING_LENGTH; i++ ) {
      string[i] = ' ';
    }
    stringPos = 0;
  }

  private void setActive( int x, int y, boolean set ) {
    if ( set ) {
      grid[y][x].setBGColour( COLOUR_ACTIVE );
    } else {
      grid[y][x].setBGColour( COLOUR_INACTIVE );
    }
  }

  public void setCursor( int x, int y ) {
    Point offset = offset( x, y );
    Point oSelected = offset( selected.x, selected.y );
    setActive( oSelected.x, oSelected.y, false );
    selected.setLocation( x, y );
    setActive( offset.x, offset.y, true );
  }

  public void applyMove() {
    int dX = this.selected.x;
    int dY = this.selected.y;
    if ( Putil.isBitSet( MOVE_RIGHT, moveFlags ) ) {
      dX += 1;
    }
    if ( Putil.isBitSet( MOVE_LEFT, moveFlags ) ) {
      dX -= 1;
    }
    if ( Putil.isBitSet( MOVE_UP, moveFlags ) ) {
      dY -= 1;
    }
    if ( Putil.isBitSet( MOVE_DOWN, moveFlags ) ) {
      dY += 1;
    }

    this.moveFlags = 0;
    dX = Putil.wrapIndex( ALPHA_WIDTH, dX );
    dY = Putil.wrapIndex( ALPHA_HEIGHT, dY );
    setCursor( dX, dY );
  }

  public void moveCursor( int direction ) {
    this.moveFlags = Putil.setBitState( direction, moveFlags, true );
  }

  public void selectActive() {
    Point offset = offset( selected.x, selected.y );
    insertChar( get( offset.x, offset.y ).getChar() );
  }

  private void moveTextCursor( int move ) {
    boolean moveToEnd = ( stringPos + move ) >= STRING_LENGTH;
    stringPos = Putil.bindIndex( STRING_LENGTH, stringPos + move );
    //highlightPos = stringPos = Putil.bindIndex( STRING_LENGTH, stringPos + move );
    if ( moveToEnd ) {
      complete = true;
      //highlightPos++;
      setCursor( end.x, end.y );
    }
    else {
      complete = false;
    }
  }

  private void insertChar( char c ) {
    if ( isSpecial( c ) ) {
      //'←' '»'
      switch ( c ) {
        case '←':
          backSpace();
          break;
        case '»':
          setState( STATE_CONFIRMED );
          break;
      }
    } else {
      string[stringPos] = c;
      moveTextCursor( +1 );
      textChanged();
    }
  }

  private void backSpace() {
    if ( !complete ) {
      string[stringPos] = ' ';
      moveTextCursor( -1 );
      string[stringPos] = ' ';
    }
    else {
      complete = false;
      string[stringPos] = ' ';
    }
      textChanged();
  }

  private boolean isSpecial( char c ) {
    for ( int i = 0; i < specialChars.length; i++ ) {
      if ( c == specialChars[i] ) {
        return true;
      }
    }
    return false;
  }

  private void drawText() {
    clearGrid( 0, 0, GameConstants.GRID_WIDTH, ALPHA_Y );
    drawString( "NEW HIGH", Color.WHITE, 4, 1, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL | FLAG_CENTER );
    drawString( "SCORE!", Color.WHITE, 4, 2, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL | FLAG_CENTER );
    drawString( "PLACE:", Color.WHITE, 0, 4, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL );
    drawString( String.valueOf( this.scoreBoard ), Color.MAGENTA, 6, 4, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL );
    drawString( String.valueOf( this.newScore ), Color.GREEN, 4, 6, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL | FLAG_CENTER );
    drawName();
  }

  private void drawName() {
    int col = 2;
    int row = 9;

    for ( int i = 0; i < STRING_LENGTH; i++ ) {
      CharacterCell cell = grid[row][col + i];
      Color bg = null;
      cell.setVisible( true );
      if ( complete || i < stringPos ) {
        bg = COLOUR_COMPLETE;
      } else if ( i == stringPos ) {
        bg = COLOUR_ACTIVE;
      } else {
        bg = COLOUR_INACTIVE;
      }
      cell.setBGColour( bg );
    }

    drawString( String.valueOf( string ), COLOUR_ACTIVE, col, row, GameConstants.GRID_WIDTH, 1, FLAG_HORIZONTAL );
  }

  private void writeKeyboard() {
    Point offset;
    drawString( "ABCDEFGHIJKLMNOPQRSTUVWXYZ  ♀♂←»", Color.WHITE, ALPHA_X, ALPHA_Y,
            ALPHA_WIDTH, ALPHA_HEIGHT, FLAG_HORIZONTAL );

    for ( int y = 0; y < ALPHA_HEIGHT; y++ ) {
      for ( int x = 0; x < ALPHA_WIDTH; x++ ) {
        offset = offset( x, y );
        grid[offset.y][offset.x].setVisible( true );
      }
    }
  }

  private Point offset( int x, int y ) {
    return new Point( x + ALPHA_X, y + ALPHA_Y );
  }

  /**
   * Begin. If score does not make the leaderboard, do nothing and return false.
   * @param score
   */
  public boolean newScore( long score ) {
    int scoreBoard = gameScore.getBoardPosition( score );
    if ( scoreBoard < 0 ) {
      return false;
    }
    setState( STATE_ENTRY );
    this.scoreBoard = scoreBoard;
    this.newScore = score;
    textChanged();
    return true;
  }

  public String getName() {
    return String.valueOf( string );
  }

  public int getState() {
    return this.state;
  }

  public void setState( int newState ) {
    if ( this.state != newState ) {
      this.state = newState;
      stateChanged();
    }
  }

  private void stateChanged() {
    switch ( this.state ) {
      case STATE_INACTIVE:
        reset();
        break;
      case STATE_ENTRY:
        break;
      case STATE_CONFIRMED:
        break;
    }
  }

  private void textChanged() {
    clearGrid( 4, 4, GameConstants.GRID_WIDTH, 1 );
    drawText();
  }
}
